#include <string.h>
#include <unistd.h>
#include "scanner.h"
#include "byte_code.h"
#include "obj.h"
#include "compiler.h"
#include "stack.h"
#include "vm.h"
#include "hash_table.h"

extern ObjFunction* globalFun;
extern const char* opCodeStrs[];

int main1(int argc, char* argv[]) {
    const char* src = "var abc = \"abc\"; var aa = 1 + 2 * 6 / 3;// comment\nprint aa;\nfun fab(n){}";
    initScanner(src);
    for(;;) {
        Token token = scanToken();
        if(token.type == TOKEN_EOF) break;
        printf("%d, %d, %.*s\n", 
            token.line, token.type, token.len, token.start);
    }
    return 0;
}

int main2(int argc, char* argv[]) {
    Chunk chunk;
    chunkInit(&chunk);
    chunkAddCode(&chunk, OP_ADD, 1);
    printf("code: %d\n", chunkGetCode(&chunk, 0));
    Value v1 = {VAL_NUMBER, 200};
    Value v2 = {VAL_NUMBER, 100};
    chunkAddConstant(&chunk, v1);
    printf("constant: %d\n", chunkGetConstant(&chunk, 0));
    chunkAddConstant(&chunk, v2);
    printf("constant: %d\n", chunkGetConstant(&chunk, 1));
    return 0;
}

int main(int argc, char* argv[]) {
    const char* src = "print \"math test:\"; var a = 1; print a + 2 * 3 / -1 + (4 - 2);\
    print \"\nglobal test:\";var b = \"Hello World!\"; print b;\
    print \"\nlocal test:\";{var a = \"cccc\"; {var a = 11; a = 22; print a;} print a;}\
    print \"\nif test:\";if(!\"1\") print 111; else print 222; print 333;\
    print \"\nwhile test:\";var i = 10; while(i) {print i;i = i - 1;}\
    print \"\ncompare test:\";print !(3 < 2);\
    print \"\nlogic test:\";print 0 and 0 or 1 or 1 and 0;\
    print \"\nfunction test:\"; fun fab(a) {if(a < 2) return a; return a * fab(a - 1);} print fab(3); print 22;"; // -3

    compile(src);
    chunkPrint(&globalFun->chunk);
    
    printf("\nvm run: \n");
    VM vm;
    vmInit(&vm, globalFun);
    run(&vm);
    return 0;
}

int main4(int argc, char* argv[]) {
    Stack stack;
    int arr[] = {1, 2};
    stack_init(&stack, 4);
    printf("after init\n");
    stack_push(&stack, arr);
    stack_push(&stack, arr + 1);
    printf("after push\n");
    printf("%d\n", *(int*)stack_pop(&stack));
    printf("%d\n", *(int*)stack_pop(&stack));
    return 0;
}

int main5(int argc, char* argv[]) {
    HashTable table;
    hashTableInit(&table, strHash, strcmp);
    hashTablePut(&table, "aa", "aaa");
    hashTablePut(&table, "bb", "bbb");
    hashTablePut(&table, "aa", "aaa2");
    hashTablePut(&table, "cc", "aaa1");
    hashTablePut(&table, "dd", "aaa1");
    hashTablePut(&table, "ee", "aaa1");
    hashTablePut(&table, "ff", "aaa1");
    hashTablePut(&table, "gg", "aaa1");
    hashTablePut(&table, "hh", "aaa1");
    const char* v1 = hashTableGet(&table, "aa");
    const char* v2 = hashTableGet(&table, "bb");
    printf("v1: %s, v2: %s, size: %d, capacity: %d\n", v1, v2, table.size, table.capacity);
    Entry removed = hashTableRemove(&table, "aa");
    printf("removed: %s\n", removed.val);
    return 0;
}

int main6(int argc, char* argv[]) {
    HashTable table;
    hashTableInit(&table, objStrHash, objStrCompare);
    ObjString* s1 = objStringCreate("aa", 2, &table);
    ObjString* s2 = objStringCreate("aa", 2, &table);
    printf("s1: %p, s2: %p, %d\n", s1, s2, s1 == s2);
    return 0;
}
